﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using MiniExcelLibs;
using MySqlX.XDevAPI.Common;
using thinger.DataConvertLib;
using thinger.MTHControlLib;
using thinger.MTHDLL;
using thinger.MTHModbusLib;
using thinger.MTHModels;

namespace thinger.MTHProject
{
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();
            this.Load += FrmMain_Load;
            //动态更新：集合中的任何变化（添加、删除、替换、移动或清空操作）都会触发 CollectionChanged 事件，这对于需要实时更新显示数据的 UI 控件非常有用。
            this.alarmList.CollectionChanged += AlarmList_CollectionChanged;

            //定时器时间
            timers.Interval = 1000;
            //不止重复一次
            timers.AutoReset = true;
            //定时器的事件
            timers.Elapsed += Timers_Elapsed;

            //定时器开始
            timers.Start();

            //窗体关闭时关闭定时器
            this.FormClosing += (sender, e) =>
            {
                timers.Stop();
            };

        }

        private void Timers_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (CommonMethods.Device.IsConnected)
            {

                this.ledStatus.Value = true;

                bool result = CommonMethods.Device["模块1温度"] != null;
                result &= CommonMethods.Device["模块1湿度"] != null;
                result &= CommonMethods.Device["模块2温度"] != null;
                result &= CommonMethods.Device["模块2湿度"] != null;
                result &= CommonMethods.Device["模块3温度"] != null;
                result &= CommonMethods.Device["模块3湿度"] != null;
                result &= CommonMethods.Device["模块4温度"] != null;
                result &= CommonMethods.Device["模块4湿度"] != null;
                result &= CommonMethods.Device["模块5温度"] != null;
                result &= CommonMethods.Device["模块5湿度"] != null;
                result &= CommonMethods.Device["模块6温度"] != null;
                result &= CommonMethods.Device["模块6湿度"] != null;


                if (result)
                {
                    string dateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                    ActualData actualData = new ActualData();

                    actualData.InsertTime = dateTime;
                    actualData.Station1Temp = CommonMethods.Device["模块1温度"].ToString();
                    actualData.Station1Humidity = CommonMethods.Device["模块1湿度"].ToString();
                    actualData.Station2Temp = CommonMethods.Device["模块2温度"].ToString();
                    actualData.Station2Humidity = CommonMethods.Device["模块2湿度"].ToString();
                    actualData.Station3Temp = CommonMethods.Device["模块3温度"].ToString();
                    actualData.Station3Humidity = CommonMethods.Device["模块3湿度"].ToString();
                    actualData.Station4Temp = CommonMethods.Device["模块4温度"].ToString();
                    actualData.Station4Humidity = CommonMethods.Device["模块4湿度"].ToString();
                    actualData.Station5Temp = CommonMethods.Device["模块5温度"].ToString();
                    actualData.Station5Humidity = CommonMethods.Device["模块5湿度"].ToString();
                    actualData.Station6Temp = CommonMethods.Device["模块6温度"].ToString();
                    actualData.Station6Humidity = CommonMethods.Device["模块6湿度"].ToString();

                    int v = actualDataManage.AddActual(actualData);
                    if (v < 0) 
                    {
                        new FrmMsgBoxWithOutAck("实施数据加入失败","请检查").Show();
                    }
                }

            }

        }

        private void FrmMain_Load(object sender, EventArgs e)
        {
            this.lblLoginName.Text = CommonMethods.sysAdmin.LoginName;
            this.lblLoginTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            naviButtons.Add(this.naviButton0);
            naviButtons.Add(this.naviButton1);
            naviButtons.Add(this.naviButton2);
            naviButtons.Add(this.naviButton3);
            naviButtons.Add(this.naviButton4);
            naviButtons.Add(this.naviButton5);

            NaviButton naviButton = new NaviButton();
            naviButton.NaviName = "集中监控";

            //打开立即跳到集中监控
            OpenForm(this.MainPanal, naviButton);

            //加载数据
            LoadData(groupPath, varlablePath);

            if (CommonMethods.Device != null)
            {
                CommonMethods.AddLog(0, "设备加载成功");
                //报警事件
                CommonMethods.Device.AlarmEvent += Device_AlarmEvent;

                cts = new CancellationTokenSource();

                Task.Run(new Action(() =>
                {
                    DeviceCommunication(CommonMethods.Device);
                }), cts.Token);
            }


        }

        //设备的文件路径
        private string devPath = Application.StartupPath + "\\Config\\Device.ini";

        //通信组的文件路径
        private string groupPath = Application.StartupPath + "\\Config\\Group.xlsx";

        //变量的文件路径
        private string varlablePath = Application.StartupPath + "\\Config\\Varlable.xlsx";

        private CancellationTokenSource cts;

        private ActualDataManage actualDataManage = new ActualDataManage();

        private SysLogManage sysLogManage = new SysLogManage();

        private int currentNavButton = 0;

        private List<NaviButton> naviButtons = new List<NaviButton>();

        /// <summary>
        /// 
        /// </summary>
        private System.Timers.Timer timers = new System.Timers.Timer();

        private DataFormat dataFormat = DataFormat.ABCD;
        //动态数据集合，当你需要在用户界面（UI）中动态显示或编辑数据集合时，
        private ObservableCollection<string> alarmList = new ObservableCollection<string>();

        //报警事件
        private void Device_AlarmEvent(bool isAlarm, Varlable varlable)
        {
            if (isAlarm)
            {
                CommonMethods.AddLog(0, $"触发{varlable.Remark}");
                alarmList.Add(varlable.Remark);

                SysLog sysLog = new SysLog();

                sysLog.VarName = varlable.VarName;
                sysLog.AlarmType = "触发";
                sysLog.Operator = CommonMethods.sysAdmin.LoginName;
                sysLog.InsertTime = DateTime.Now.ToString();
                sysLog.Note = varlable.Remark;

                int v = sysLogManage.addSysLog(sysLog);
                if (v < 0) 
                {
                    new FrmMsgBoxWithOutAck("触发警报记录失败","请检查").Show();
                }
            }
            else
            {
                CommonMethods.AddLog(1, $"解除{varlable.Remark}");
                alarmList.Remove(varlable.Remark);
                
                SysLog sysLog = new SysLog();
                
                sysLog.VarName = varlable.VarName;
                sysLog.AlarmType = "触发";
                sysLog.Operator = CommonMethods.sysAdmin.LoginName;
                sysLog.InsertTime = DateTime.Now.ToString();
                sysLog.Note = varlable.Remark;

                int v = sysLogManage.addSysLog(sysLog);
                if (v < 0)
                {
                    new FrmMsgBoxWithOutAck("解除警报记录失败", "请检查").Show();
                }
            }
        }
        private void AlarmList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //这里要考虑多线程
            this.Invoke(new Action(() => {

                switch (this.alarmList.Count)
                {
                    case 0:
                        this.scrollingText1.Text = "通信无异常";
                        this.ledStatus.Value = true;
                        break;
                    default:
                        this.scrollingText1.Text = String.Join(" ", alarmList);
                        this.ledStatus.Value = false;
                        break;
                }

            }));

            
        }
        private void DeviceCommunication(Device device)
        {
            //cts.IsCancellationRequested检查是否取消了请求
            while (!cts.IsCancellationRequested)
            {
                if (device.IsConnected)
                {
                    //连接后读数据
                    device.Groups.ForEach(a =>
                    {
                        byte[] result = null;
                        int reLength = 0;
                        if (a.StoreArea == "输出线圈0x" || a.StoreArea == "输入线圈1x")
                        {
                            switch (a.StoreArea)
                            {
                                case "输出线圈0x":
                                    result = CommonMethods.ModbusTCP.ReadOutputCoils(a.Start, a.Length);
                                    
                                    reLength = ShortLib.GetByteLengthFromBoolLength(a.Length);
                                    break;
                                case "输入线圈1x":
                                    result = CommonMethods.ModbusTCP.ReadInputCoils(a.Start, a.Length);
                                    reLength = ShortLib.GetByteLengthFromBoolLength(a.Length);
                                    break;
                                default:
                                    break;
                            }
                            if (result != null && result.Length == reLength)
                            {
                                //解析
                                foreach (var item in a.Varlables)
                                {
                                    DataType dataType = (DataType)Enum.Parse(typeof(DataType), item.DataType, true);

                                    int start = item.Start - a.Start;

                                    switch (dataType)
                                    {
                                        case DataType.Bool:

                                            item.VarValue = BitLib.GetBitFromByteArray(result, start, Convert.ToInt32(item.OffsetOrLength));

                                            break;

                                        default:
                                            break;
                                    }

                                    //线性处理
                                    item.VarValue = MigrationLib.GetMigrationValue(item.VarValue, item.VarScale.ToString(), item.Offset.ToString()).Content;

                                    //数据处理
                                    device.UpDataVarValue(item);
                                }
                            }
                            else
                            {
                                device.IsConnected = false;
                                
                            }

                        }
                        else
                        {
                            switch (a.StoreArea)
                            {
                                case "输出寄存器4x":
                                    result = CommonMethods.ModbusTCP.ReadOutputRegisters(a.Start, a.Length);
                                    reLength = a.Length * 2;
                                    break;
                                case "输入寄存器3x":
                                    result = CommonMethods.ModbusTCP.ReadInputRegisters(a.Start, a.Length);
                                    reLength = a.Length * 2;
                                    break;
                                default:
                                    break;
                            }

                            if (result != null && result.Length == reLength)
                            {
                                foreach (var item in a.Varlables)
                                {
                                    DataType dataType = (DataType)Enum.Parse(typeof(DataType), item.DataType, true);

                                    int start = item.Start - a.Start;

                                    start *= 2;

                                    switch (dataType)
                                    {
                                        case DataType.Bool:
                                            item.VarValue = BitLib.GetBitFrom2BytesArray(result, start, (int)item.OffsetOrLength, dataFormat == DataFormat.BADC || dataFormat == DataFormat.CDAB);
                                            break;
                                        case DataType.Byte:
                                            item.VarValue = ByteLib.GetByteFromByteArray(result, dataFormat == DataFormat.BADC || dataFormat == DataFormat.CDAB ? start : start + 1);
                                            break;
                                        case DataType.Short:
                                            item.VarValue = ShortLib.GetShortFromByteArray(result, start, dataFormat);
                                            break;
                                        case DataType.UShort:
                                            item.VarValue = UShortLib.GetUShortFromByteArray(result, start, dataFormat);
                                            break;
                                        case DataType.Int:
                                            item.VarValue = IntLib.GetIntFromByteArray(result, start, dataFormat);
                                            break;
                                        case DataType.UInt:
                                            item.VarValue = UIntLib.GetUIntFromByteArray(result, start, dataFormat);
                                            break;
                                        case DataType.Float:
                                            item.VarValue = FloatLib.GetFloatFromByteArray(result, start, dataFormat);
                                            break;
                                        case DataType.Double:
                                            item.VarValue = DoubleLib.GetDoubleFromByteArray(result, start, dataFormat);
                                            break;
                                        case DataType.Long:
                                            item.VarValue = LongLib.GetLongFromByteArray(result, start, dataFormat);
                                            break;
                                        case DataType.ULong:
                                            item.VarValue = ULongLib.GetULongFromByteArray(result, start, dataFormat);
                                            break;
                                        case DataType.String:
                                            item.VarValue = StringLib.GetStringFromByteArrayByEncoding(result, start, (int)item.OffsetOrLength, Encoding.ASCII);
                                            break;
                                        case DataType.ByteArray:
                                            item.VarValue = ByteArrayLib.GetByteArrayFromByteArray(result, start, (int)item.OffsetOrLength);
                                            break;
                                        case DataType.HexString:
                                            item.VarValue = StringLib.GetHexStringFromByteArray(result, start, (int)item.OffsetOrLength);
                                            break;
                                        default:
                                            break;
                                    }

                                    //线性处理
                                    item.VarValue = MigrationLib.GetMigrationValue(item.VarValue, item.VarScale.ToString(), item.Offset.ToString()).Content;

                                    //数据处理
                                    device.UpDataVarValue(item);
                                }
                            }
                            else
                            {
                                device.IsConnected = false;
                                
                            }
                        }




                    });
                }
                else
                {
                    //非首次连接
                    if (device.ReConncentSign)
                    {
                        CommonMethods.ModbusTCP?.Disconnect();
                        Thread.Sleep(device.ReConnectTime);
                    }
                    //连接
                    device.IsConnected = CommonMethods.ModbusTCP.Connect(device.IPAdress, device.Port);

                    if (device.ReConncentSign)
                    {
                        CommonMethods.AddLog(device.IsConnected ? 0 : 2, device.IsConnected ? "重新连接成功" : "重新连接失败");
                    }
                    else 
                    {
                        device.ReConncentSign = true;
                        CommonMethods.AddLog(device.IsConnected ? 0 : 2, device.IsConnected ? "首次连接成功" : "首次连接失败");
                    }
                }
            }
        }

        //加载dev,group,varlable
        private void LoadData(string groupPath, string varlablePath)
        {
            if (CommonMethods.Device == null)
            {
                CommonMethods.AddLog(1, "请先配置设备");
                return;
            }
            List<Group> groups = new List<Group>();
            try
            {
                groups = MiniExcel.Query<Group>(groupPath).ToList();
            }
            catch (Exception)
            {

                CommonMethods.AddLog(2, "请正确配置通信组");
                return;
            }
            List<Varlable> varlables = new List<Varlable>();
            try
            {
                varlables = MiniExcel.Query<Varlable>(varlablePath).ToList();
            }
            catch (Exception)
            {

                CommonMethods.AddLog(2, "请正确配置变量");
                return;

            }

            if (groups != null && varlables != null && groups.Count > 0 && varlables.Count > 0)
            {
                foreach (var group in groups)
                {
                    group.Varlables = varlables.FindAll(a => a.GroupName == group.GroupName).ToList();
                }

                CommonMethods.Device.Groups = groups;
            }
            else
            {
                CommonMethods.AddLog(1, "请先配置通信组和变量");
                return;
            }







        }

        

        /// <summary>
        /// 导航按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CommonNavi_Click(object sender, EventArgs e)
        {
            if (sender is NaviButton navi)
            {
                if (Enum.IsDefined(typeof(FromNames), navi.NaviName))
                {
                    FromNames fromNames = (FromNames)Enum.Parse(typeof(FromNames), navi.NaviName, true);
                    switch (fromNames)
                    {

                        case FromNames.参数设置:
                            if (!CommonMethods.sysAdmin.ParamSet)
                            {
                                new FrmMsgBoxWithOutAck("没有参数设置权限", "请先设置权限").Show();
                                return;
                            }
                            break;
                        case FromNames.配方管理:
                            if (!CommonMethods.sysAdmin.Recipe)
                            {
                                new FrmMsgBoxWithOutAck("没有配方权限", "请先设置权限").Show();
                                return;
                            }
                            break;
                        case FromNames.报警追溯:
                            if(!CommonMethods.sysAdmin.HistoryTrend)
                            {
                                new FrmMsgBoxWithOutAck("没有报警追溯权限", "请先设置权限").Show();
                                return;
                            }
                            break;
                        case FromNames.历史追溯:
                            if (!CommonMethods.sysAdmin.HistoryLog)
                            {
                                new FrmMsgBoxWithOutAck("没有历史追溯权限", "请先设置权限").Show();
                                return;
                            }
                            break;
                        case FromNames.用户管理:
                            if (!CommonMethods.sysAdmin.UserManage)
                            {
                                new FrmMsgBoxWithOutAck("没有用户管理权限", "请先设置权限").Show();
                                return;
                            }
                            break;
                        default:
                            break;
                    }

                    //打开通用窗体
                    OpenForm(this.MainPanal, navi);

                    //切换导航选中
                    IsSelected(navi);

                    //修改标题

                    UpdateTitle(this.lblTitle, navi);
                }

            }
        }

        private void OpenForm(Panel mainPanal, NaviButton navi)
        {

            int count = mainPanal.Controls.Count;

            int closeCount = 0;

            bool isFind = false;

            FromNames fromNames = (FromNames)Enum.Parse(typeof(FromNames), navi.NaviName, true);
            //mainPanal中的全部控件
            for (int i = 0; i < count; i++)
            {
                Control control = mainPanal.Controls[i - closeCount];

                if (control is Form form)
                {


                    if (form.Text.Trim().ToString() == navi.NaviName)
                    {
                        //找到的窗体提前
                        form.BringToFront();
                        isFind = true;
                        break;
                    }
                    else
                    {
                        if (fromNames > FromNames.临界窗体)
                        {
                            form.Close();
                            closeCount++;
                            isFind = false;
                        }
                    }
                }
            }

            //没找到对应的窗体
            if (!isFind)
            {
                Form form = null;
                switch (fromNames)
                {
                    case FromNames.集中监控:
                        form = new FrmMonitor();
                        //委托绑定方法
                        CommonMethods.AddLog = ((FrmMonitor)form).AddLog;
                        break;
                    case FromNames.参数设置:
                        form = new FrmParamSet(devPath);
                        break;
                    case FromNames.配方管理:
                        form = new FrmRecipe(devPath);
                        break;
                    case FromNames.报警追溯:
                        form = new FrmAlarm();
                        break;
                    case FromNames.历史追溯:
                        form = new FrmAlarm();
                        break;
                    case FromNames.用户管理:
                        form = new FrmUserManage();
                        break;
                    default:
                        break;
                }

                if (form != null)
                {
                    //设置非顶层
                    form.TopLevel = false;

                    //去边框
                    form.FormBorderStyle = FormBorderStyle.None;
                    //设置父窗体
                    form.Parent = mainPanal;
                    //设置窗体填充
                    form.Dock = DockStyle.Fill;

                    form.BringToFront();

                    form.Show();

                }

            }

        }

        private void UpdateTitle(Label lblTitle, NaviButton navi)
        {
            lblTitle.Text = navi.NaviName.Trim().ToString();
        }

        private void IsSelected(NaviButton navi)
        {



            foreach (var item in this.TopPanel.Controls.OfType<NaviButton>())
            {
                if (navi.NaviName.Trim().ToString() == item.NaviName.Trim().ToString())
                {
                    navi.IsSelect = true;
                }
                else
                {
                    item.IsSelect = false;
                }

            }
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            this.Close();
            
        }

        #region 减少闪烁
        /// <summary>
        /// 将所有的控件一起加载出来，再显示以减少闪烁
        /// </summary>
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;

                cp.ExStyle |= 0x02000000;

                return cp;
            }

        }
        #endregion

        private void btnRight_Click(object sender, EventArgs e)
        {
            currentNavButton++;
            if (currentNavButton < naviButtons.Count)
            {

                CommonNavi_Click(naviButtons[currentNavButton], null);
            }
            else 
            {
                currentNavButton--;
            }
        }

        private void btnLeft_Click(object sender, EventArgs e)
        {
            currentNavButton--;
            if (currentNavButton >= 0)
            {

                CommonNavi_Click(naviButtons[currentNavButton], null);
            }
            else
            {
                currentNavButton++;
            }
        }
    }
}
